﻿using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using TianShu.Application.Dtos;
using Volo.Abp.Data;
using Volo.Abp.Domain;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.MultiTenancy;
using Volo.Abp.ObjectExtending;
using Volo.Abp.Application;
using TianShu.TenantManagement.Dal.Abstracts.Entities;
using TianShu.TenantManagement.Dal.Abstracts.Manager;
using TianShu.TenantManagement.Service.Abstracts.TenantService.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Application.Dtos;
using Volo.Abp;
using System.Linq.Expressions;
using Volo.Abp.Domain.Shared;

namespace TianShu.TenantManagement
{
    public class TenantAppService : CrudAppService<TenantEntity, TenantDto, Guid, TenantCreateDto, TenantUpdateDto>, ITenantAppService
    {
        protected IRepository<TenantEntity, Guid> TenantRepository { get; }
        protected ITenantManager TenantManager { get; }
        protected IDistributedEventBus DistributedEventBus { get; }

        public TenantAppService(
            IRepository<TenantEntity, Guid> tenantRepository,
            ITenantManager tenantManager,
            IDistributedEventBus distributedEventBus) : base(tenantRepository)
        {
            TenantRepository = tenantRepository;
            TenantManager = tenantManager;
            DistributedEventBus = distributedEventBus;
        }

        public override Expression<Func<TenantEntity, bool>> GetQueryWhereCondition(List<UrlParams> urlParams)
        {
            if (urlParams.TryGetKeyword(out string keyword))
            {
                return e => e.Code.Contains(keyword) ||e.Name.Contains(keyword);
            }
            return base.GetQueryWhereCondition(urlParams);
        }

        public override async Task<ResultDto<TenantDto>> CreateAsync(TenantCreateDto dto)
        {
            dto.ExtraProperties["ContactUserName"] = dto.ContactUserName;
            dto.ExtraProperties["ContactUserPhone"] = dto.ContactUserPhone;
            dto.ExtraProperties["ContactAddress"] = dto.ContactAddress;

            await ValidateCode(dto.Code, dto.Name);

            return await base.CreateAsync(dto);
        }
        private async Task ValidateCode(string code, string name, Guid? tenantId = null)
        {
            var codeEntity = await Repository.FindAsync(e => e.Code == code || e.Name == name);
            if (codeEntity != null && codeEntity.Id != tenantId)
            {
                throw new UserFriendlyException("租户已存在");
            }
        }

        protected override async Task<ResultDto<bool>> UpdateValidAsync(TenantEntity idEntity, TenantUpdateDto dto)
        {
            dto.ExtraProperties["ContactUserName"] = dto.ContactUserName;
            dto.ExtraProperties["ContactUserPhone"] = dto.ContactUserPhone;
            dto.ExtraProperties["ContactAddress"] = dto.ContactAddress;

            await ValidateCode(dto.Code, dto.Name, idEntity.Id);

            return await base.UpdateValidAsync(idEntity, dto);
        }

        public async Task<ResultDto<TenantDto>> GetByCodeAsync(string code)
        {
            var codeEntity = await Repository.FindAsync(e => e.Code == code);
            if (codeEntity == null)
            {
                return new ResultDto<TenantDto>("租户不存在");
            }
            var result = ObjectMapper.Map<TenantEntity, TenantDto>(codeEntity);
            return new ResultDto<TenantDto>(result);
        }

        public virtual async Task<ResultDto<object>> GetDefaultConnectionStringAsync(Guid id)
        {
            var tenant = await TenantManager.FindAndConnectionStringAsync(e => e.Id == id);
            var result = tenant?.FindDefaultConnectionString();
            return new ResultDto<object>((object)result);
        }

        public virtual async Task<ResultDto<bool>> UpdateDefaultConnectionStringAsync(Guid id, TenantConnectionStringUpdateInput input)
        {
            var tenant = await TenantManager.FindAndConnectionStringAsync(e => e.Id == id);
            tenant.SetDefaultConnectionString(input.DefaultConnectionString);
            await TenantManager.UpdateAndConnectionStringAsync(tenant);
            return new ResultDto<bool>(true);
        }

        public virtual async Task<ResultDto<bool>> DeleteDefaultConnectionStringAsync(Guid id)
        {
            var tenant = await TenantManager.FindAndConnectionStringAsync(e => e.Id == id);
            tenant.RemoveDefaultConnectionString();
            await TenantManager.UpdateAndConnectionStringAsync(tenant);
            return new ResultDto<bool>(true);
        }
    }
}
